/*
 * @Date         : 2024-05-22 07:45:41 星期3
 * @Author       : xut
 * @Description  : Nest 以两种可能的方式支持 GRPC 流处理程序：
 * 1. @GrpcStreamMethod 装饰器，配合 RxJS Subject + Observable 处理程序：可用于在 Controller 方法内部编写响应或传递给 Subject/Observable 消费者，例子见 hero 模块的 hero-service.controller.ts
 * 2. @GrpcStreamCall 装饰器，纯 GRPC 调用流处理程序：传递给某个执行程序可能很有用，该执行程序将处理 Node 标准 Duplex 流处理程序的其余分派。例子见 hello 模块的 hello-service.controller.ts
 */
import * as grpc from '@grpc/grpc-js';
import { Controller } from '@nestjs/common';
import { GrpcStreamCall } from '@nestjs/microservices';
import { HelloRequest, HelloResponse } from './hello.type';

@Controller()
export class HelloServiceController {
  @GrpcStreamCall('HelloService')
  bidiHello(
    requestStream: grpc.ServerDuplexStream<HelloRequest, HelloResponse>,
  ) {
    // request header 接收
    const incomingTimestamps = requestStream.metadata.get('timestamp');

    if (incomingTimestamps.length > 0) {
      console.log('Timestamp from metadata:');
      for (const [index, value] of incomingTimestamps.entries()) {
        console.log(` ${index}. ${value}`);
      }
    }

    // response header 响应
    const responseHeaderMetadata = new grpc.Metadata();
    responseHeaderMetadata.set('timestamp', new Date().toISOString());
    requestStream.sendMetadata(responseHeaderMetadata);

    requestStream.on('data', (message) => {
      console.log('🚀 ~ HelloController ~ message:', JSON.stringify(message));

      requestStream.write({ reply: 'Hello, World!' });
    });

    requestStream.on('end', () => {
      // response trailers 响应
      const responseTrailerMetadata = new grpc.Metadata();
      responseTrailerMetadata.set('timestamp', new Date().toISOString());
      requestStream.end(responseTrailerMetadata);
    });
  }

  @GrpcStreamCall('HelloService')
  LotsOfGreetings(
    requestStream: grpc.ServerReadableStream<HelloRequest, HelloResponse>,
    callback: grpc.sendUnaryData<HelloResponse>,
  ) {
    // request header 接收
    const incomingTimestamps = requestStream.metadata.get('timestamp');

    if (incomingTimestamps.length > 0) {
      console.log('Timestamp from client metadata:');
      for (const [index, value] of incomingTimestamps.entries()) {
        console.log(` ${index}. ${value}`);
      }
    }
    // response header
    const responseHeaderMetadata = new grpc.Metadata();
    responseHeaderMetadata.set('timestamp', new Date().toISOString());
    requestStream.sendMetadata(responseHeaderMetadata);

    requestStream.on('data', (message) => {
      console.log(
        '🚀 ~ HelloController ~ lotsOfGreeting ~ message:',
        JSON.stringify(message),
      );
    });
    requestStream.on('end', () => {
      // response trailers 响应
      const responseTrailerMetadata = new grpc.Metadata();
      responseTrailerMetadata.set('timestamp', new Date().toISOString());

      callback(
        null,
        { reply: 'lotsOfGreeting: Hello, world!' },
        responseTrailerMetadata,
      );
    });
  }
}
